package com.boot.mall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.boot.common.constant.CartConstant;
import com.boot.common.utils.R;
import com.boot.mall.cart.feign.ProductFeignService;
import com.boot.mall.cart.interceptor.CartInterceptor;
import com.boot.mall.cart.service.CartService;
import com.boot.mall.cart.to.UserInfoTo;
import com.boot.mall.cart.vo.Cart;
import com.boot.mall.cart.vo.CartItem;
import com.boot.mall.cart.vo.SkuInfoVo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private ThreadPoolExecutor executor;

    /**
     * 添加商品到购物车
     * @param skuId
     * @param num
     * @return
     */
    @Override
    public CartItem addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        CartItem cartItem = new CartItem();
        // 将当前用户需要操作的Redis中存储的Hash对象绑定
        BoundHashOperations<String, Object, Object> options = getCartOptions();
        ObjectMapper mapper = new ObjectMapper();

        // 异步调用查询sku信息方法
        CompletableFuture<SkuInfoVo> skuResponse = CompletableFuture.supplyAsync(() -> {
            // 远程调用接口查询当前Sku的所有信息
            R res = productFeignService.info(skuId);
            SkuInfoVo skuInfo = mapper.convertValue(res.get("skuInfo"), SkuInfoVo.class);
            return skuInfo;
        }, executor);

        // 异步调用查询sku的销售属性
        CompletableFuture<List<String>> attrResponse = CompletableFuture.supplyAsync(() -> {
            List<String> skuSaleAttr = productFeignService.getSkuSaleAttr(skuId);
            return skuSaleAttr;
        }, executor);

        // 阻塞式获取查询结果
        SkuInfoVo skuInfoVo = skuResponse.get();
        List<String> attrSaleValue = attrResponse.get();

        // Redis中是否含有key
        Object hasKey = options.get(skuId.toString());
        if (hasKey != null){
            // 当前Sku信息在Redis中存在，修改商品数量即可
            CartItem item = JSON.parseObject(hasKey.toString(),CartItem.class);     //从Redis中获取当前购物项的信息

            int count = num + item.getCount();  //计算当前数量
            item.setCount(count);
            // 在原先销售基础上添加新的销售属性
            List<String> oldSkuAttr = item.getSkuAttr();
            // TODO 判断当前属性是否已经存在
            for (String s : attrSaleValue) {
                oldSkuAttr.add(s);
            }
            item.setSkuAttr(oldSkuAttr);
            String string = JSON.toJSONString(item);
            BeanUtils.copyProperties(item,cartItem);
            // 将购物项放入Redis中，指定过期时间
            options.put(skuId.toString(),string);
            // TODO 指定过期时间
        }else {
            // 当前Sku信息在Redis中不存在，添加到Redis中
            cartItem.setSkuId(skuId);   //skuId
            cartItem.setCheck(false);    //被选中
            cartItem.setCount(num); //数量
            cartItem.setImage(skuInfoVo.getSkuDefaultImg());    //图片地址
            cartItem.setTitle(skuInfoVo.getSkuTitle()); //sku标题
            cartItem.setPrice(skuInfoVo.getPrice());    //sku价格
            cartItem.setSkuAttr(attrSaleValue); //sku的销售属性
            // 将购物项放入Redis中，指定过期时间
            String string = JSON.toJSONString(cartItem);
            options.put(skuId.toString(),string);
        }

        return cartItem;
    }

    @Override
    public Cart getCart() throws ExecutionException, InterruptedException {
        Cart cart = new Cart();

        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();

        String cartKey = CartConstant.CART_PREFIX;      //拼接购物车的key值

        if (userInfoTo.getUserId() == null){
            // 用户未登录
            cartKey += userInfoTo.getUserKey();
            // 查询用户购物车数据
            List<CartItem> items = getCartItemsFromRedis(cartKey);
            cart.setItems(items);
            return cart;
        }

        // -------用户已经登录情况--------

        // 当登录用户存在临时购物车时，将临时购物车和已登录购物车合并
        String keyNotLogin = CartConstant.CART_PREFIX + userInfoTo.getUserKey();
        if (stringRedisTemplate.hasKey(keyNotLogin)){
            // 当用户存在未登录的用户车时，获取用户未登录的购物车
            List<CartItem> items = getCartItemsFromRedis(keyNotLogin);
            if (items != null && items.size() > 0){
                // 将购物车添加到用户购物车当中
                for (CartItem item : items) {
                    addToCart(item.getSkuId(),item.getCount());
                }
            }
            // 删除登录用户的临时购物车
            ClearCart(keyNotLogin);
        }
        // 用户登录状态
        cartKey += userInfoTo.getUserId();
        // 获取已登录的购物车
        List<CartItem> items = getCartItemsFromRedis(cartKey);

        cart.setItems(items);
        return cart;
    }

    // 删除购物车
    private void ClearCart(String keyNotLogin) {
        stringRedisTemplate.delete(keyNotLogin);
    }

    // 根据key的ID获取用户的购物车数据
    @Override
    public List<CartItem> getCartItemsFromRedis(String cartKey) {
        ObjectMapper mapper = new ObjectMapper();
        // 获取用户的购物车
        BoundHashOperations<String, Object, Object> options = stringRedisTemplate.boundHashOps(cartKey);
        // 取出购物车中所有的购物项
        List<Object> cartItemStr = options.values();
        if (cartItemStr != null && cartItemStr.size() > 0){
            // 将每一项购物项转换成购物项对象并返回收集
            List<CartItem> items = cartItemStr.stream().map(item -> {
                String json = (String) item;
                System.out.println(item);
                CartItem cartItem = JSON.parseObject(json, CartItem.class);
                return cartItem;
            }).collect(Collectors.toList());
            // 设置购物项，其他属性动态计算
            return items;
        }
        return null;
    }

    /**
     * 修改sku的选中状态
     * @param skuId
     * @param isChecked
     */
    @Override
    public void checkCartItem(Long skuId, Integer isChecked) {

        BoundHashOperations<String, Object, Object> options = getCartOptions();
        CartItem cartItem = getCartItem(skuId);
        // 设置选中状态
        cartItem.setCheck(isChecked == 1);
        String string = JSON.toJSONString(cartItem);
        // 修改存储的信息
        options.put(skuId.toString(),string);
    }


    /**
     * 修改购物项的数量
     * @param skuId
     * @param num
     */
    @Override
    public void changeItemCount(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> options = getCartOptions();
        CartItem cartItem = getCartItem(skuId);
        // 设置新的数量
        int newCount = num;
        // 修改成新数量
        cartItem.setCount(newCount);
        String string = JSON.toJSONString(cartItem);
        options.put(skuId.toString(),string);
    }

    /**
     * 删除购物项
     * @param skuId
     * @return
     */
    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> options = getCartOptions();
        options.delete(skuId.toString());
    }

    /**
     * 查询选中的购物项
     * @param memberId
     * @return
     */
    @Override
    public List<CartItem> getCheckItems(Long memberId) {
        // 获取当前购物车的所有购物项
        List<CartItem> cartItems = getCartItemsFromRedis(CartConstant.CART_PREFIX + memberId.toString());
        // 判断每一条购物项是否被选中，被选中的添加到集合返回
        List<CartItem> collect = cartItems.stream()
                .filter(cartItem -> cartItem.getCheck())
                .map(cartItem -> {
                    // 查询当前sku的最新价格信息
                    BigDecimal newPrice = productFeignService.getSkuCurrentPrice(cartItem.getSkuId());
                    cartItem.setPrice(newPrice);
                    return cartItem;
                })
                .collect(Collectors.toList());
        return collect;
    }

    /**
     * 获取当前请求用户的购物车信息
     * @return
     */
    private BoundHashOperations<String, Object, Object> getCartOptions() {

        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        // 判断用户是否登录
        String cartKey = "";
        if (userInfoTo.getUserId() == null){
            // 用户未登录时，Redis中存储购物车数据的Key是用户的随机Key值
            cartKey = CartConstant.CART_PREFIX + userInfoTo.getUserKey();
        }else {
            // 用户已经登录时，Redis中存储购物车数据的Key是用户的id值
            cartKey = CartConstant.CART_PREFIX + userInfoTo.getUserId();
        }

        BoundHashOperations<String, Object, Object> options = stringRedisTemplate.boundHashOps(cartKey);

        return options;
    }

    /**
     * 根据skuId获取购物项
     * @param skuId
     * @return
     */
    private CartItem getCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartItemOps = getCartOptions();
        String s = (String) cartItemOps.get(skuId.toString());
        CartItem cartItem = JSON.parseObject(s, CartItem.class);
        return cartItem;
    }
}
